package other.edan.system.utils;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.util.IOUtils;
import com.rkhd.platform.sdk.common.OauthConfig;
import com.rkhd.platform.sdk.http.CommonData;
import com.rkhd.platform.sdk.http.CommonHttpClient;
import com.rkhd.platform.sdk.http.HttpResult;
import com.rkhd.platform.sdk.log.Logger;
import com.rkhd.platform.sdk.log.LoggerFactory;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * ClassName: other.xsy.paas.utils.ZipUtil
 * Description: 代码打包工具类
 * date: 2023/05/06
 *
 * @author
 */
public class ZipUtil {

    private static final Logger logger = LoggerFactory.getLogger();

    private static final int BUFFER_SIZE = 2 * 1024;

    /**
     * 压缩成ZIP
     * @throws RuntimeException
     */
    public static String toZip(String zipFileName)
            throws RuntimeException {
        long start = System.currentTimeMillis();
        ZipOutputStream zos = null;
        try {
            String projectPath = System.getProperty("user.dir");
            String zipFile = projectPath + "/" + zipFileName;
            System.out.println("projectPath = " + projectPath);
            FileOutputStream outputStream = new FileOutputStream(zipFile);
            zos = new ZipOutputStream(outputStream);
            File sourceFile = new File(projectPath + "/src");
            compress(sourceFile, zos, "");
            long end = System.currentTimeMillis();
            logger.info("压缩完成，耗时：" + (end - start) + " ms");
            return zipFile;
        } catch (Exception e) {
            logger.error("zip error from ZipUtils, error:" + e);
            return "";
        } finally {
            if (zos != null) {
                IOUtils.close(zos);
            }
        }

    }

    /**
     * 递归压缩方法
     *
     * @param sourceFile       源文件
     * @param zos              zip输出流
     * @param name             压缩后的名称
     *
     * @throws Exception
     */
    private static void compress(File sourceFile, ZipOutputStream zos, String name) throws Exception {
        byte[] buf = new byte[BUFFER_SIZE];
        if (sourceFile.isFile()) {
            if (sourceFile.getName().equals("other.edan.system.utils.ZipUtil")){
                return;
            }
            // 向zip输出流中添加一个zip实体，构造器中name为zip实体的文件的名字
            zos.putNextEntry(new ZipEntry(name));
            // copy文件到zip输出流中
            int len;
            FileInputStream in = new FileInputStream(sourceFile);
            while ((len = in.read(buf)) != -1) {
                zos.write(buf, 0, len);
            }
            // Complete the entry
            zos.closeEntry();
            in.close();
        } else {
            File[] listFiles = sourceFile.listFiles();
            if (listFiles == null || listFiles.length == 0) {
                // 空文件夹的处理
                zos.putNextEntry(new ZipEntry(""));
                // 没有文件，不需要文件的copy
                zos.closeEntry();
            } else {
                for (File file : listFiles) {
                    if ("ZipUtil.java".equals(file.getName())){
                        continue;
                    }
                    // 判断是否需要保留原来的文件结构
                    if (StringUtils.isBlank(name)){
                        compress(file, zos, file.getName());
                    }else {
                        compress(file, zos, name + "/" + file.getName());
                    }

                }
            }
        }
    }

    /**
     * 删除文件
     *
     * @param filePath
     * @return
     */
    public static boolean deleteFile(String filePath) {
        boolean flag = false;
        File file = new File(filePath);
        if (!file.exists()) {
            return flag;
        }
        if (!file.isDirectory()) {
            return flag;
        }
        String[] tempList = file.list();
        File temp;
        for (int i = 0; i < tempList.length; i++) {
            if (filePath.endsWith(File.separator)) {
                temp = new File(filePath + tempList[i]);
            } else {
                temp = new File(filePath + File.separator + tempList[i]);
            }
            if (temp.isFile()) {
                temp.delete();
            }
            if (temp.isDirectory()) {
                // 先删除文件夹里面的文件
                deleteFile(filePath + "/" + tempList[i]);
                // 再删除空文件夹
                deleteFile(filePath + "/" + tempList[i]);
                flag = true;
            }
        }
        return flag;
    }

    /**
     * 删除zip
     *
     * @param filePath
     * @return
     */
    public static void deleteZip(String filePath) {
        File file = new File(filePath);
        // zip文件  判断 是否存在
        if (file.getName().endsWith(".zip")) {
            if (file.delete()) {
                logger.info("zip文件已经删除");
            } else {
                logger.info("zip文件删除失败");
            }
        }
    }

    /**
     * 文件上传
     * @param file
     * @param commitMsg
     * @return
     * @throws IOException
     */
    public static JSONObject upload(String packageName, File file, String commitMsg) {
        CloseableHttpClient client = HttpClients.custom().build();
        JSONObject jsonObject = null;
        OauthConfig oauthConfig = new OauthConfig();
        String domain = oauthConfig.getDomain();
        String url = domain + "/rest/metadata/v2.0/dx/logic/packages/actions/upload?packageName=" + packageName;
        HttpPost post = new HttpPost(url);
        try {
            //获取access_token
            String accessToken = getAccessToken();
            if (StringUtils.isBlank(accessToken)){
                logger.info("获取access_token失败");
            }
            if(null != file){
                MultipartEntityBuilder builder = MultipartEntityBuilder.create();
                builder.addBinaryBody("file",file, ContentType.MULTIPART_FORM_DATA, file.getName());
                builder.addTextBody("commitMsg", commitMsg);
                HttpEntity httpEntity = builder.build();
                post.setEntity(httpEntity);
                post.addHeader("accept", "*/*");
                post.addHeader("connection", "Keep-Alive");
                post.addHeader("user-agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
                post.addHeader("Accept-Encoding", "gzip, deflate, br");//头部放文件上传的head可自定义
                post.addHeader("Authorization", accessToken);
            }
            HttpResponse response = client.execute(post);
            int statusCode = response.getStatusLine().getStatusCode();
            if(200 != statusCode){//如果请求成功并且有响应
                logger.info("请求失败");
            }
            InputStream content = response.getEntity().getContent();
            String str = getStringByInputStream(content);
            jsonObject = JSONObject.parseObject(str);
        }catch (Exception e){
            logger.error("代码上传异常, error:" + e);
        } finally {
            post.releaseConnection();
            IOUtils.close(client);
        }
        return jsonObject;
    }

    /**
     * input流转String
     * @param inputStream
     * @return
     */
    public static String getStringByInputStream(InputStream inputStream){
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        try {
            byte[] b = new byte[10240];
            int n;
            while ((n = inputStream.read(b)) != -1) {
                outputStream.write(b, 0, n);
            }
        } catch (Exception e) {
            try {
                inputStream.close();
                outputStream.close();
            } catch (Exception e1) {
            }
        }
        return outputStream.toString();
    }

    /**
     * 获取access_token
     */
    private static String getAccessToken() {
        OauthConfig oauthConfig = new OauthConfig();
        String userName = oauthConfig.getUserName();
        String password = oauthConfig.getPassword();
        String securityCode = oauthConfig.getSecurityCode();
        String clientId = oauthConfig.getClientId();
        String clientSecret = oauthConfig.getClientSecret();
        String oauthUrl = oauthConfig.getOauthUrl() + "?grant_type=password" + "&client_id=" +  clientId + "&client_secret=" +  clientSecret + "&username=" +  userName + "&password=" +  password +  securityCode;
        CommonData commonData = new CommonData();
        commonData.setCall_type("GET");
        commonData.setCallString(oauthUrl);
        CommonHttpClient client = new CommonHttpClient();
        client.setContentEncoding("UTF-8");
        client.setContentType("application/json");
        HttpResult result =  client.execute(commonData);
        if (result != null && StringUtils.isNotBlank(result.getResult())) {
            JSONObject jsonObject = JSONObject.parseObject(result.getResult());
            if (jsonObject.containsKey("access_token")) {
                return jsonObject.getString("access_token");
            } else {
                if (jsonObject.containsKey("error_description")) {
                    logger.info(jsonObject.getString("error_description"));
                } else {
                    logger.info(jsonObject.toString());
                }
            }
        } else {
            logger.info("can not get the accessToken,please check your config");
        }
        return "";
    }

    /**
     * 获取包名
     * @return
     */
    private static String getPackageName(){
        String packageName = ZipUtil.class.getPackage().getName();
        String[] split = packageName.split("\\.");
        if (split.length > 3){
            packageName = split[0] + "." + split[1] + "." + split[2];
        }
        return packageName;
    }

    /**
     * 打包并上传
     */
    public static void packAndUpload(String fileName, String msg){
        String zip = toZip(fileName);
        File file = new File(zip);
        if (StringUtils.isBlank(msg)){
            msg = "代码上传";
        }
        JSONObject upload = upload(getPackageName(), file, msg);
        if (!"200".equals(upload.get("code"))){
            logger.info("上传失败:" + JSONObject.toJSONString(upload));
        }else {
            logger.info("上传成功：" + JSONObject.toJSONString(upload));
        }
    }

    public static void main(String[] args) {
        packAndUpload("PAAS.zip", "");
    }

}